#    Copyright 2008, 2009 Tri-County Electric Cooperative, St. Matthews, South Carolina
#    This file is part of COOPIP.
#    COOPIP is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#    COOPIP is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with COOPIP.  If not, see <http://www.gnu.org/licenses/>.

import os
import datetime
import shutil

#************************BEGIN Add Include Files to Path************************
import sys
NeededPaths=['/opt/coopip/djangoproject/include', '/opt/coopip/djangoproject']
for path in NeededPaths:
    if(not path in sys.path):
        sys.path.append(path)
#************************END   Add Include Files to Path************************
from django.contrib.gis.geos import *
import os, time, psycopg2, datetime
#********************Setup psycopg2 and django section********************
PathDjangoRoot="/opt/coopip/"
if(not PathDjangoRoot in sys.path):
    sys.path.append(PathDjangoRoot)
from django.core.management import setup_environ
import djangoproject
from djangoproject import settings
setup_environ(settings)
from models import *
#********************Setup psycopg2 and django section********************

from django.template import Context, loader
from django.http import HttpResponse
from django import forms
import os, sys, ldap, django
import datetime
import djangoproject.settings
import COOPIP_Misc, COOPIP_Form
import djangoproject.models.ipbase


def GetUserNameOrIPAddress(request):
    if(bool(request.user.username)):
        UserName=str(request.user.username)
    else:
        UserName=str(request.META['REMOTE_ADDR']) 
    return UserName


def CheckIfCurrentlyLoggedIn(request):
    if request.user.is_anonymous():
        return False, "You are not currently logged in.  Please login through the Main Menu."
    else:
        return True, "Welcome to the Tri-County Intranet, " + request.user.username + "."

def AttemptLDAPAuthentication(Username, Password):
    Username=''.join(character for character in Username if character.isalnum())
    Server = "ldap://192.168.100.8"
    DN = "CN=Tech Tech,OU=SBSUsers,OU=Users,OU=MyBusiness,DC=tcec2010,DC=local"
    Secret = "*#Switch*#"

    Base = "OU=SBSUsers,OU=Users,OU=MyBusiness,DC=tcec2010,DC=local"
    Scope = ldap.SCOPE_SUBTREE
    Filter = "(&(objectClass=user)(sAMAccountName=Tech Tech))"
    Attrs = ["CN"]
    l = ldap.initialize(Server)
    l.set_option(ldap.OPT_REFERRALS, 0)
    l.protocol_version=3
    l.simple_bind_s(DN, Secret)
    searchFilter = 'SamAccountName=' + Username
    ldap_result_id=l.search(Base, Scope, searchFilter, ['SamAccountName', 'givenname', 'sn', 'mail'])
    while True:
        result_type, result_data = l.result(ldap_result_id, 0)
        if(result_data == []):
            break
        Full=result_data[0][0]
        Start=Full.find("CN=") + len("CN=")
        End=Start + Full[Start:].find(",")
        CN=Full[Start:End]
    #Now Attempt to Bind to LDAP using the CN
    l = ldap.initialize(Server)
    l.set_option(ldap.OPT_REFERRALS, 0)
    l.protocol_version=3
    l.simple_bind_s('CN=' + CN + ',' + Base, Password)
    ldap_result_id=l.search(Base, Scope, searchFilter, ['SamAccountName', 'givenname', 'sn', 'mail', 'memberOf'])
    BindSuccessful=False
    LDAPUserGroups=[]
    while True:
        result_type, result_data = l.result(ldap_result_id, 0)
        if(result_data == []):
            break
        Full=result_data[0][0]
        Start=Full.find("CN=") + len("CN=")
        End=Start + Full[Start:].find(",")
        BindCN=Full[Start:End] 
        if(BindCN == CN): #Verify that we bound to the correct account.
            BindSuccessful=True
            Groups=result_data[0][1]['memberOf']
            LDAPUserGroups=[]
            for group in Groups:
                Start=group.find("CN=") + len("CN=")
                End=Start + group[Start:].find(",")
                GroupName=group[Start:End]
                if('COOPIP_' in GroupName): 
                    LDAPUserGroups.append(GroupName)
    return BindSuccessful, LDAPUserGroups  


    
def UpdateLDAPUserGroupMembership(user, LDAPUserGroups):
    for lDAPGroup in LDAPUserGroups:  #Make sure the groups exist
        try:
            DjangoGroup = django.contrib.auth.models.Group.objects.get(name__exact=lDAPGroup)
        except:
            DjangoGroup = django.contrib.auth.models.Group()
            DjangoGroup.name=lDAPGroup
            DjangoGroup.save()
    CurrentUserGroups=[]
    for currentUserGroup in user.groups.values_list():
        CurrentUserGroups.append(currentUserGroup[1])
    
    for djangoGroup in django.contrib.auth.models.Group.objects.all():  #Add/Remove the user from the Django Groups based on LDAP
        ShouldBeInCurrentGroup=False    #Make sure the user is a member of all groups in LDAPUserGroups
        for lDAPUserGroup in LDAPUserGroups:
            if(lDAPUserGroup == djangoGroup.name):
                ShouldBeInCurrentGroup=True
        if(ShouldBeInCurrentGroup):
            if(not djangoGroup.name in CurrentUserGroups):
                user.groups.add(djangoGroup)
        elif(djangoGroup.name in CurrentUserGroups):
            user.groups.remove(djangoGroup)
    

    




def COOPIPAuthenticate(request, RequiredGroupMembership, CheckGroupMembershipOnly=False):
    """Custom Authentication using LDAP for TCEC"""
    Permission, Message = CheckIfCurrentlyLoggedIn(request)  #First, check to see if the user is already logged in
    Username=request.user.username
    if(not str(type(RequiredGroupMembership)) == "<type 'list'>"):
        RequiredGroupMembership = [RequiredGroupMembership]
    if(Permission):
        user=request.user
        CurrentUserGroups=[]
        for currentUserGroup in user.groups.values_list():
            CurrentUserGroups.append(currentUserGroup[1])
        #raise(Exception(str(RequiredGroupMembership)))
        for group in RequiredGroupMembership:
            if(group in CurrentUserGroups and user.is_active):
                return Permission, Message, Username
    if(CheckGroupMembershipOnly):  #would have returned already if was already logged in and a member of an appropriate group
        return False, "You do not have permissions for this application, ", user.username

   
    try:
        Username=request.POST['Username']
        Password=request.POST['Password']
    except:
        Username, Password = '', False

    if(not Username):
        return False, "You are not currently logged in.", Username
    try:
        Permission, LDAPUserGroups = AttemptLDAPAuthentication(Username, Password)  #Next, attempt to authenticate using LDAP with the supplied username and password
    except:
        Permission = False
        LDAPUserGroups=[]

    if(Permission):
        #Need to create an account if it does not exist
        #Set the accounts password to the current password supplied (valid since authentication worked)
        from django.contrib.auth.models import User
        try:
            user = User.objects.get(username__exact=Username)
        except:
            user = User.objects.create_user(Username, Username + '@tce.coop', Password)
            user.is_active = True
        user.set_password(Password)
        user.save()
        UpdateLDAPUserGroupMembership(user, LDAPUserGroups)
        user=django.contrib.auth.authenticate(username=Username, password=Password)
        django.contrib.auth.login(request, user)
        CurrentUserGroups=[]
        for currentUserGroup in user.groups.values_list():
            CurrentUserGroups.append(currentUserGroup[1])
        for group in RequiredGroupMembership:
            if(RequiredGroupMembership in CurrentUserGroups and user.is_active):
                return True, "Welcome to the Tri-County Intranet, " + user.username + ".", user.username                 

    #Last-chance authentication against the Django database
    try:
        user = User.objects.get(username__exact=Username)
    except:
        return False, 'You are not currently logged in.', Username
    if(user.check_password(Password)):
        user=django.contrib.auth.authenticate(username=Username, password=Password)
        django.contrib.auth.login(request, user)
        CurrentUserGroups=[]
        for currentUserGroup in user.groups.values_list():
            CurrentUserGroups.append(currentUserGroup[1])
        for group in RequiredGroupMembership:
            if(group in CurrentUserGroups and user.is_active):
                return True, "Welcome to the Tri-County Intranet, " + user.username + ".", user.username    
        return False, "You do not have permissions for this application, " + Username, Username
    return False, "You are not currently logged in.", Username, Username




